package com.sky.service.impl;

import com.sky.entity.Orders;
import com.sky.entity.Top10NameAndNum;
import com.sky.entity.User;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ReportMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.vo.OrderReportVO;
import com.sky.vo.SalesTop10ReportVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.vo.UserReportVO;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
public class ReportServiceImpl implements ReportService {
    @Autowired
    ReportMapper reportMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;


    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        List<Orders> list = orderMapper.selectByOrderTime(beginTime,endTime, Orders.COMPLETED);
        List<LocalDate> localDateList = new ArrayList<>();
        List<BigDecimal> bigDecimalList = new ArrayList<>();
        localDateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            localDateList.add(begin);
        }
        for (LocalDate localDate:localDateList){
            LocalDateTime bt = LocalDateTime.of(localDate, LocalTime.MIN).minusSeconds(1);
            LocalDateTime et = LocalDateTime.of(localDate, LocalTime.MAX).plusSeconds(1);
            BigDecimal amount = new BigDecimal("0.00");
            for (Orders orders :list){
                if (orders.getOrderTime().isBefore(et)&&orders.getOrderTime().isAfter(bt)){
                    amount=amount.add(orders.getAmount());
                }
            }
            bigDecimalList.add(amount);
        }
        TurnoverReportVO turnoverReportVO
                = new TurnoverReportVO(StringUtils.join(localDateList,",")
                ,StringUtils.join(bigDecimalList,","));
        return turnoverReportVO;
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        Long userNum = userMapper.selectUserNum();
        List<User> userList = userMapper.selectByTime(beginTime,endTime);
        List<LocalDate> localDateList = new ArrayList<>();
        List<Long> userNumList = new ArrayList<>();
        userNumList.add(userNum);
        List<Long> newUserNumList = new ArrayList<>();
        localDateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            localDateList.add(begin);
        }
        for (int i = localDateList.size()-1;i>=0;i--){
            LocalDateTime bt = LocalDateTime.of(localDateList.get(i), LocalTime.MIN).minusSeconds(1);
            LocalDateTime et = LocalDateTime.of(localDateList.get(i), LocalTime.MAX).plusSeconds(1);
            Long newUserNum = new Long(0);
            for (User user :userList){
                if (user.getCreateTime().isBefore(et)&& user.getCreateTime().isAfter(bt)){
                    newUserNum += 1;
                }
            }
            userNum-=newUserNum;
            userNumList.add(0,userNum);
            newUserNumList.add(0,newUserNum);
        }
        userNumList.remove(0);

        UserReportVO userReportVO
                = new UserReportVO(StringUtils.join(localDateList,","),
                StringUtils.join(userNumList,","),
                StringUtils.join(newUserNumList,","));
        return userReportVO;
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        List<Orders> list = orderMapper.selectByOrderTime(beginTime,endTime, Orders.COMPLETED);
        List<LocalDate> localDateList = new ArrayList<>();
        localDateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            localDateList.add(begin);
        }
        Long validOrdersNum = new Long(0);
        Long ordersNum = new Long(0);
        List<Long> OrdersNumList = new ArrayList<>();
        List<Long> validOrdersNumList = new ArrayList<>();
        for (LocalDate localDate:localDateList){
            LocalDateTime bt = LocalDateTime.of(localDate, LocalTime.MIN).minusSeconds(1);
            LocalDateTime et = LocalDateTime.of(localDate, LocalTime.MAX).plusSeconds(1);
            Long validDayOrdersNum = new Long(0);
            Long dayOrdersNum = new Long(0);
            for (Orders orders :list){
                if (orders.getOrderTime().isBefore(et)&&orders.getOrderTime().isAfter(bt)){
                    dayOrdersNum+=1;
                    if (orders.getStatus()==5){
                        validDayOrdersNum+=1;
                    }
                }
            }
            ordersNum+=dayOrdersNum;
            validOrdersNum+=validDayOrdersNum;
            OrdersNumList.add(dayOrdersNum);
            validOrdersNumList.add(validDayOrdersNum);
        }
        OrderReportVO orderReportVO = OrderReportVO.builder()
                .dateList(StringUtils.join(localDateList,","))
                .orderCountList(StringUtils.join(OrdersNumList,","))
                .validOrderCountList(StringUtils.join(validOrdersNumList,","))
                .totalOrderCount(ordersNum.intValue())
                .validOrderCount(validOrdersNum.intValue())
                .orderCompletionRate(ordersNum/(double)validOrdersNum).build();
        return orderReportVO;
    }

    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        List<String> nameList = orderDetailMapper.selectByOrderTime(beginTime,endTime,Orders.COMPLETED);
        if (nameList.isEmpty()) return null;
        Map<String,Integer> map = new HashMap<>();
        List<Top10NameAndNum> list = new ArrayList<>();
        for (String name : nameList){
            if (map.containsKey(name)){
                map.put(name,map.get(name)+1);
            }
            else {
                map.put(name,1);
            }
        }
        for (Map.Entry<String,Integer> entry : map.entrySet())
            list.add(new Top10NameAndNum(entry.getKey(),entry.getValue()));
        list.sort(Comparator.comparingInt(Top10NameAndNum::getNumber).reversed());
        String name = new String(list.get(0).getName());
        String number = new String(list.get(0).getNumber().toString());
        for (int i = 1;i<list.size()-1&i<9;i++){
            name=name+","+list.get(i).getName();
            number=number+","+list.get(i).getNumber().toString();
        }
        return new SalesTop10ReportVO(name,number);
    }
}
